/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package game.experts.combine;

import analysys.HECAlignmentHit;
import game.datahandling.dataenvelopes.base.PrimaryStructure;
import game.encodings.OutputEncoding;
import game.experts.Expert;
import utils.Msg;
import utils.Profile;

/**
 *
 * @author emanuele
 */
public class SSPSingleCertaintyWeightHintedCombinerExpert extends SSPSingleWeightHintedCombinerExpert {

    @Override
    protected double getWeight(Expert<PrimaryStructure> e) {
        double weight;
        double accuracy, sumaccuracy;
        double wrongcertainty, sumwrongcert;
        double rightcertainty, sumrightcert;

        if (this.current.hints.isEmpty())
            return 1;

        sumaccuracy = 0; sumwrongcert = 0; sumrightcert = 0;
        for (HECAlignmentHit hint: this.current.hints) {
            OutputEncoding pred = e.predict(new PrimaryStructure(hint.hitWholePri));

            String prediction = pred.decode().toString();
            Profile profile = pred.getProfile();

            int errors = this.getDifferences(prediction, hint.hitWholeSec);
            double curraccuracy = 1 - ((double)errors) / ((double)prediction.length());

            double currwrongcert = 0;
            double currrightcert = 0;
            for (int i = 0; i < profile.length(); i++) {
                double[] col = profile.getColumn(i);
                int jmax = this.getIMax(col);
                int jsecondmax = this.getISecondMax(col);
                double currcertainty = Math.abs(col[jmax] - col[jsecondmax]);
                if (prediction.charAt(i) == hint.hitWholeSec.charAt(i))
                    currrightcert += currcertainty;
                else
                    currwrongcert += currcertainty;
            }

            sumaccuracy += curraccuracy;
            sumrightcert += ( currrightcert / ((double)(prediction.length() - errors)) );
            sumwrongcert += ( currwrongcert / ((double)errors) );
        }

        accuracy = sumaccuracy / ((double)this.current.hints.size());
        if (accuracy > 0.999) {
            Msg.info("Accuracy higher than 0.999!!!");
            Msg.info(e.getName() + " on " + this.current.input.toString());
            accuracy = 0.999;
        }
        rightcertainty = sumrightcert / ((double)this.current.hints.size());
        wrongcertainty = sumwrongcert / ((double)this.current.hints.size());

        weight = Math.exp(accuracy * rightcertainty / wrongcertainty);

        return weight;
    }

    int getIMax(double[] arr) {
        int imax = 0;
        for (int i = 1; i < arr.length; i++)
            if (arr[i] > arr[imax])
                imax = i;
        return imax;
    }

    int getISecondMax(double[] arr) {
        double[] arr2 = arr.clone();
        arr2[this.getIMax(arr)] = -1;
        return this.getIMax(arr2);
    }
}
